<h1>Occasionally Connected Application Framework for Windows 8.1 Store Apps</h1>

<h2>Overview</h2>

<p>Being able to work offline is an expected feature of mobile/tablet applications. For data-driven applications, it means that developers will have to store user-specific application data locally, and implement a data synchronization mechanism that keeps the local and server data in sync. By incorporating the occasionally connected application framework into your code, you can extend your Windows 8.1 Applications to download unstructured data and still function when disconnected from the network. 
This documentation describes the design and features of the occasionally connected application framework that you can incorporate into Windows Store applications. </p>

<h2>Conceptual View</h2>

<h2>General Concepts</h2>

<p>[Pic]</p>

<h3>Local Storage &amp; Synchronization Context</h3>

<p>All actions that a developer is concerned with reside in the Local and Remote folder containers. When building an application, the code can work with Local and Remote file instances directly. Behind the scenes, file instances delegate work to the associated folder which in turn delegate to the associated storage engine. All responsibility for interacting with local or remote storage are contained in implementations of the Remote and Local storage interfaces.
By default, the OCAF uses SQLite as the local database to track the status of files in local folder. This storage is used to compare files when the application is back online.</p>

<ul>
<li>ISyncFolder </li>
<li>ISyncFile</li>
<li>ISyncContext</li>
</ul>

<h3>Local Folder</h3>

<p>A local folder represents the local folder on disk and it�s mapping to a remote container in Windows Azure blob storage or any other remote storage.</p>

<h3>Remote Folder</h3>

<p>[ Empty ]</p>

<h3>Class View of Local Storage</h3>

<p>[Pic]</p>

<h2>Setup</h2>

<h3>Software Requirements</h3>

<p>To work with the occasionally connected application framework, you must ensure that your system meets the following minimum software requirements:</p>

<ol>
<li>Windows 8.1 Operating System</li>
<li>Visual Studio 2013</li>
<li>3rd Party libraries &amp; additional references (set Visual Studio to download required Nuget packages)
--1.    SQLite.dll � Download the SQLite Visual Studio extension for Windows 8.1: <a href="http://sqlite.org/2013/sqlite-winrt81-3080002.vsix">http://sqlite.org/2013/sqlite-winrt81-3080002.vsix</a>
--2.    Packages installed via Nuget. This will happen automatically if you have the package manager set up to download dependencies.
---1.   MVVMLight 4.2.30.0<br>
---2.   Windows Azure Mobile Services 1.1.2 
---4.   Sqlite-net 1.0.7
---5.   Windows Azure Storage-Preview 3.0.2.0-preview (Win 8 version is still in CTP)</li>
</ol>

<h3>Remote Server Setup</h3>

<p>In this example, the remote server is responsible for</p>

<ol>
<li>Providing a SAS for access to your blob storage account</li>
<li>Linking the users device to the blob storage account for that user</li>
<li>Offloading file upload/download directly to the blob storage service</li>
</ol>

<p>It could be expanded to support distributing users across multiple storage accounts, provide read-only privileges to specific containers, or complete user validation prior to providing a SAS key.</p>

<p>We have included a sample project (TED.WindowsAzure.Unplugged.Mobile.RemoteStorage.AzureBlob) in the toolkit which will help you build a remote file server functionality using Windows Azure blob storage and Mobile Services. If you prefer to use a WebAPI server, you can easily rewrite this script using C# and update WindowsAzureBlobStorage accordingly to call the new API.</p>

<p>In our example we have remote containers of blobs in Windows Azure. We�ve defined a Windows Azure storage account and secure key in a script running windows Azure Mobile Services. You will need to update the script with your own windows Azure storage account.</p>

<p>The script is included in the Script directory of the TED.WindowsAzure.Unplugged.Mobile.RemoteStorage.AzureBlob project</p>

<p>[Pic]</p>

<p>You will need to add this script to Windows Azure Mobile Services before the remote storage implementation will work.</p>

<p>[Pic]</p>

<h2>How to Use the API?</h2>

<h3>Setting Up a New Sync-enabled MobileServiceClient</h3>

<p>The central class in the framework is called TEDMobileServiceClient you will need to instantiate TED mobile service client and pass Azure Mobile Services endpoint and application key </p>

<p><code>
var client = new TEDMobileServiceClient(new Uri("&lt;Mobile Services uri&gt;"), "Key");
</code></p>

<p>Then initialize synchronization context. This can be used to plug in additional custom providers.</p>

<p><code>
await client.SyncContext.InitializeAsync(new WindowsAzureBlobStorage(client));
</code></p>

<p>To separate files into independent areas, the concept of sync folders is implemented. Acquiring a sync folder, is done like this</p>

<p><code>
ISyncFolder folder = await client.SyncContext.GetSyncFolderAsync("MyFiles");
</code></p>

<p>The name (e.g. 'MyFiles') represents the folder name both on the server side as well as the local device side. Once a sync folder is acquired, the framework offers you multiple methods of adding, modifying and synchronizing files.</p>

<h3>Syncronizing</h3>

<p>The two main operations are pulling down files from the remote storage and pushing changed versions or new files back up.
To allow you fine-granular synchronization, the two methods are provided on the level of each individual sync folder:</p>

<p><code>
await folder.PullAsync();
await folder.PushAsync();
</code></p>

<p>Multiple events provide updates on the progress of either push or pull. See API reference for details.</p>

<p><code>
folder.PullStarted += (s, e) =&gt;
{
    Log.Info("Pull started");
};
folder.PullCompleted += (s, e) =&gt;
{
    Log.Info("Pull completed");
};
folder.PullProgressChanged += (s, e) =&gt;
{
    Log.Info(e.RemoteFile + " + " + e.LocalFile);
};
folder.SyncListBuilt += (s, e) =&gt;
{
    Log.Info(e.SyncFiles.Count());
};
</code></p>

<h3>Adding a New File</h3>

<p>To add a newly created file first you need to create it in the local sync folder:
ISyncFile file = await folder.CreateFileAsync("newfile.txt");</p>

<p>The returned ISyncFile instance is a reference to the entry in the local table of content. Through the object you can next open a WinRT IRandomAccessStream on the file. Since we�re using .NET StreamWriter API we first need to convert the WinRT stream to a .NET stream. Then we can for write to the file.</p>

<p><code>
IRandomAccessStream rtStream = (await file.OpenWriteAsync());
Stream = rtStream.AsStreamForWrite();
using (var s = new StreamWriter(stream))
{
    s.Write("Hello World");
}
</code></p>

<p>Finally we need to let the framework know that the updates have been finished</p>

<p><code>
await file.CommitAsync();
</code></p>

<p>During the next push, the new file will be automatically uploaded to the remote storage.</p>

<h3>Modifying a Downloaded File Directly</h3>

<p>To modify an already downloaded file in the local file system, you need to first get a reference to it by name.</p>

<p><code>
ISyncFile file = await folder.LookupAsync("existingFile.txt");
</code></p>

<p>Once that is done, you can manipulate the file through the stream API similar to the last example.</p>

<p><code>
await file.OpenWriteAsync();
await file.OpenReadAsync();
</code></p>

<p>Don't forget to commit the written changes at the end.</p>

<p><code>
await file.CommitAsync();
</code></p>

<p>During the next push, again the modified file will be automatically uploaded to the remote storage.</p>

<h3>Deleting a file</h3>

<p>Deleting a file is similar to modifying it. Get a reference to a file first and call delete on it.</p>

<p><code>
ISyncFile file = await folder.LookupAsync("deleteme.txt");
await file.DeleteAsync();
</code></p>

<p>The file will be deleted from the remote storage during the next push.</p>

<h2>API Reference</h2>

<h3>Methods</h3>

<pre><code>PushAsync   Pushes all locally modified items in the local storage to the associated remote storage.
</code></pre>

<p>PullAsync   Pulls all remote items from the associated remote storage.
ReadAsync   Returns all local files in the LocalStorageFolder
LookupAsync Returns a single or null file based on ID or name
FlushAsync  Marks all files which are undefined as ready to Sync
CreateFileAsync Creates a 'undefined' (not inserted) local file based on a user defined name
OpenReadAsync   Opens a readable stream containing the specified instance of the file
TruncateAsync   Removes all items from the local Folder 
InsertAndCommitAsync    Insret a file and mark ready to sync
UpdateAndCommitAsync    Update a file and mark it ready to sync
CancelAsync Undo all work in progress files</p>

<h3>Events</h3>

<pre><code>PullStarted     Occurs when the pull has started.
</code></pre>

<p>PullProgressChanged     Occurs every time pull has a progress on one file
PullCompleted   Occurs when the pull is completed
PushStarted     Occurs when the push has started
PushProgressChanged     Occurs when the push is completed
SyncListBuilt   Occurs when list of files to be synchronized has been built</p>

<h3>Extending the API</h3>

<pre><code>OCAF has been designed to be easily extensible. You can extend the API to meet the requirements of a wide variety of situations. You can easily change local &amp; remote containers as well as SQLite with you own supported local database.  
</code></pre>

<p>IRemoteFileStorage  WindowsAzureBlobStorage
ILocalFileStorage<br>
ISyncFileStateStorage   Currently implements an integration with a SQLite database.</p>

<h3>Limitations</h3>

<pre><code>The framework still has some rough edges and needs some time to address these limitations:
</code></pre>

<p>1.  Multiple users reading and writing the files at same time will have undesirable effects. The server does not implement any history or versioning so last update wins.
2.  Limited conflict resolution � We are evaluating the use of sync policies to define how the API will react when synchronizing data changes. However, there is no current implementation in place
3.  Manual Pull/Push only � There is no automatic synchronization available. The app must call pull() and push() at regular intervals
4.  No notification of changes � It is up to the developer to implement a notification system for the app as it is not currently built into the framework</p>

<h3>Final Words</h3>

<pre><code>The code base for this framework should be considered a version 0.5. We are releasing this sample code to the community to get early feedback and determine which features to implement based on developer demand. Regardless, this code sample is definitely usable in the right situations.
</code></pre>
